package com.example.demo.javaTest;

import org.apache.commons.io.FileUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

public class FileIOStream {

    @Test
    public void testFile() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        System.out.println(courseFile);
        //创建File指代具体文件
        //new File可以指代目录/文件/不存在的路径，可以带盘符绝对路径，可以相对路径“项目名/路径”
        File f1 = new File(courseFile + "/src/files/testFile/a.txt");//\\等同于/，也可使用分隔符File.separator拼接
        System.out.println(f1.length());//文件大小
        System.out.println(f1.exists());
        System.out.println(f1.isFile());
        System.out.println(f1.isDirectory());
        System.out.println(f1.getName());
        System.out.println(f1.length());
        long l1 = f1.lastModified();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(l1));
        System.out.println(f1.getPath());
        System.out.println(f1.getAbsolutePath());

        //创建文件
        File f2 = new File(courseFile + "/src/files/testFile/b.txt");
        System.out.println(f2.createNewFile());//已存在则返回false
        //创建一级文件夹
        File f3 = new File(courseFile + "/src/files/testFile/test");//已存在则返回false，多级文件夹返回false
        System.out.println(f3.mkdir());
        //创建多级文件夹
        File f4 = new File(courseFile + "/src/files/testFile/test2/test2");//已存在则返回false
        System.out.println(f4.mkdirs());
        //删除文件或空文件夹，但不能删除非空文件夹（需递归删除）
        System.out.println(f1.delete());
        System.out.println(f2.delete());
        System.out.println(f3.delete());
        System.out.println(f4.delete());
        //获取文件夹下一级文件名
        File f5 = new File(courseFile + "/src/files/");
        String[] names = f5.list();
        for (String name : names) {
            System.out.println(name);
        }
        //获取文件夹下一级文件对象(功能更强大)
        File[] files = f5.listFiles();//文件或路径不存在或权限不足返回null，空文件夹返回长度为0数组，非空文件夹包含隐藏文件
        for (File file : files) {
            System.out.println(file.getAbsolutePath());
        }
        //搜索
        searchFile(new File(courseFile + "/src/files/searchFile"), "search.txt");
    }

    @Test
    public void testIO() throws Exception {
        //字符集
        //ASCII：只有英文数字符号，占1字节
        //GBK：增加了中文，汉字占2字节，英文数字占1字节
        //UTF-8：unicode万国码的一种编码方式，汉字占3字节，英文数字占1字节
        //编解码字符集需一致，否则乱码
        //英文和数字被大多数字符集兼容，一般不乱码

        //编码：byte[] getByte(编码方式)
        String data = "a我b";
        byte[] bytes = data.getBytes();//默认按平台字符集UTF-8
        System.out.println(Arrays.toString(bytes));
        byte[] bytes1 = data.getBytes("GBK");
        System.out.println(Arrays.toString(bytes1));
        //解码：String(byte[],解码方式)
        System.out.println(new String(bytes));
        System.out.println(new String(bytes1));
        System.out.println(new String(bytes1, "GBK"));
    }

    @Test
    public void testFileOutputStream() throws Exception {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        System.out.println(courseFile);
        //创建文件字节流，接通源文件
        FileOutputStream os = new FileOutputStream(courseFile + "/src/files/fileStream/testRead.txt", true);
        os.write(97);//a
        byte[] bytes = "ab492吃d9sdg是s0fsd9f".getBytes();
        os.write(bytes, 1, bytes.length - 1);//排除了第一个字节"a"
        os.write("\r\n".getBytes());
        os.close();
    }

    @Test
    public void testFileInputStream() throws Exception {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        System.out.println(courseFile);
        //创建文件字节流，接通源文件
        FileInputStream is = new FileInputStream(courseFile + "/src/files/fileStream/testRead.txt");
        //读取文件字节，性能差，汉字会乱码
        int b;
        while ((b = is.read()) != -1) {
            System.out.print((char) b);
        }
        System.out.println("----");
        //关闭
        is.close();

        //性能有所提升，汉字依然乱码
        FileInputStream is2 = new FileInputStream(courseFile + "/src/files/fileStream/testRead.txt");
        byte[] buffer = new byte[3];//每次读取3个字节
        int len;
        while ((len = is2.read(buffer)) != -1) {
            System.out.print(new String(buffer, 0, len));
        }
        System.out.println("----");
        is2.close();

        //一次性读取小文件
        String path = courseFile + "/src/files/fileStream/testRead.txt";
        FileInputStream is3 = new FileInputStream(path);
        File file = new File(path);
        byte[] buffer2 = is3.readAllBytes();
        System.out.println(new String(buffer2));
        is3.close();
    }

    @Test
    public void testFileCopy() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        System.out.println(courseFile);
        try (
                InputStream is = new FileInputStream(courseFile + "/src/files/fileStream/testRead.txt");
                OutputStream os = new FileOutputStream(courseFile + "/src/files/fileStream/testCopy.txt");
        ) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testFileReader() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                Reader fr = new FileReader(courseFile + "/src/files/fileStream/testRead.txt");
                Reader fr2 = new FileReader(courseFile + "/src/files/fileStream/testRead.txt");
        ) {
            //单个字符读取，不会乱码
            int c;
            while ((c = fr.read()) != -1) {
                System.out.print((char) c);
            }

            //多个字符读取
            char[] buffer = new char[3];
            int len;
            while ((len = fr2.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testFileWriter() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                Writer fw = new FileWriter(courseFile + "/src/files/fileStream/testOut.txt", true);
        ) {
            //单个字符读取，不会乱码
            fw.write(97);
            fw.write("b");
            fw.write("492吃d9sdg是s0fsd9f", 0, "492吃d9sdg是s0fsd9f".length());
            fw.write("\r\n");
            char[] buffer = {'a', 'b'};
            fw.write(buffer);
            fw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testBufferedByteStream() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                InputStream is = new FileInputStream(courseFile + "/src/files/bufferedStream/testBufferedRead.txt");
                InputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream(courseFile + "/src/files/bufferedStream/testBufferedCopy.txt");
                OutputStream bos = new BufferedOutputStream(os);
        ) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testBufferedCharStream() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                Reader fr = new FileReader(courseFile + "/src/files/bufferedStream/testBufferedRead.txt");
                BufferedReader br = new BufferedReader(fr);
                Reader fr2 = new FileReader(courseFile + "/src/files/bufferedStream/testBufferedRead.txt");
                BufferedReader br2 = new BufferedReader(fr2);

                Writer fw = new FileWriter(courseFile + "/src/files/bufferedStream/testBufferedOut.txt", true);
                BufferedWriter bw = new BufferedWriter(fw);
        ) {
            char[] buffer = new char[3];
            int len;
            while ((len = br.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, len));
            }

            String line;
            while ((line = br2.readLine()) != null) {
                System.out.println(line);
            }

            bw.write(97);
            bw.write("b");
            bw.write("492吃d9sdg是s0fsd9f", 0, "492吃d9sdg是s0fsd9f".length());
            bw.newLine();
            char[] buffer2 = {'a', 'b'};
            bw.write(buffer2);
            bw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testTransferStream() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                InputStream is = new FileInputStream(courseFile + "/src/files/transferStream/testTransferRead.txt");
                Reader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);

                OutputStream os = new FileOutputStream(courseFile + "/src/files/transferStream/testTransferCopy.txt");
                OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(osw);
        ) {
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.write("\r\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testPrintStream() throws IOException {
        //获取项目路径
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                PrintStream ps = new PrintStream(courseFile + "/src/files/printStream/testPrintStream.txt", StandardCharsets.UTF_8);
                PrintWriter pw = new PrintWriter(courseFile + "/src/files/printStream/testPrintWriter.txt", StandardCharsets.UTF_8);
        ) {
            ps.write(97);
            ps.println('a');
            ps.println("使1");
            ps.println(true);
            ps.println(99.9);

            pw.write(97);
            pw.println('a');
            pw.println("使1");
            pw.println(true);
            pw.println(99.9);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testDataStream() throws IOException {
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                DataOutputStream dos = new DataOutputStream(new FileOutputStream(courseFile + "/src/files/dataStream/testDataStream.txt"));
                DataInputStream dis = new DataInputStream(new FileInputStream(courseFile + "/src/files/dataStream/testDataStream.txt"));
        ) {
            dos.writeInt(97);
            dos.writeDouble(99.9);
            dos.writeBoolean(true);
            dos.writeUTF("是");

            int i = dis.readInt();
            System.out.println(i);
            double d = dis.readDouble();
            System.out.println(d);
            boolean b = dis.readBoolean();
            System.out.println(b);
            String s = dis.readUTF();
            System.out.println(s);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testSequelizeStream() throws IOException {
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        try (
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(courseFile + "/src/files/sequelizeStream/testSequelizeStream.txt"));
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(courseFile + "/src/files/sequelizeStream/testSequelizeStream.txt"));
        ) {
            LocalDateTime start1 = LocalDateTime.of(2029, 8, 10, 11, 11, 11);
            oos.writeObject(start1);

            LocalDateTime o = (LocalDateTime) ois.readObject();
            System.out.println(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testCommonsIO() throws IOException {
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        //common-io
        FileUtils.copyFile(new File(courseFile + "/src/files/common-io/source.txt"), new File(courseFile + "/src/files/common-io/copy.txt"));
        FileUtils.copyDirectory(new File(courseFile + "/src/files/common-io/source/"), new File(courseFile + "/src/files/common-io/copy/"));
        FileUtils.deleteDirectory(new File(courseFile + "/src/files/common-io/copy/"));
        //java1.7
        Files.copy(Path.of(courseFile + "/src/files/common-io/source/"), Path.of(courseFile + "/src/files/common-io/copy/"));
        System.out.println(Files.readString(Path.of(courseFile + "/src/files/common-io/source.txt")));
    }

    @Test
    public void testProperty() throws IOException {
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        //写入
        Properties properties = new Properties();
        properties.setProperty("a", "1");
        properties.setProperty("是", "2");
        properties.setProperty("3", "使");
        properties.store(new FileWriter(courseFile + "/src/files/property/user.properties"), "my comments");

        //读取
        Properties properties2 = new Properties();
        properties2.load(new FileReader(courseFile + "/src/files/property/user.properties"));
        System.out.println(properties2);
        Set<String> keys = properties2.stringPropertyNames();
        for (String key : keys) {
            String value = properties2.getProperty(key);
            System.out.println(key + "---" + value);
        }
        properties2.forEach((k, v) -> {
            System.out.println(k + "---" + v);
        });
    }

    @Test
    public void testXML() throws IOException, DocumentException {
        File directory = new File("");// 参数为空
        String courseFile = directory.getCanonicalPath();
        SAXReader saxReader = new SAXReader();
        //XML解析为document
        Document document = saxReader.read(courseFile + "/src/files/xml/hello.xml");
        //获取根元素
        Element root = document.getRootElement();
        System.out.println(root.getName());
        //获取根元素下的一级子元素
        List<Element> elements = root.elements("user");
        for (Element element : elements) {
            System.out.println(element.getName());//获取标签名
            System.out.println(element.elementText("name"));//获取子元素文本
            System.out.println(element.elementTextTrim("地址"));//获取子元素文本，去除前后空格
            System.out.println(element.attributeValue("id"));//获取单个属性
            List<Attribute> attributes = element.attributes();
            //获取元素下所有属性
            for (Attribute attribute : attributes) {
                System.out.println(attribute.getName() + "---" + attribute.getValue());
            }
        }
        Element people = root.element("people");//查找标签
        System.out.println(people.getText());
        //不建议使用dom4j写入xml，而是通过IO拼接写入
        //约束：标签名需统一英文或中文，约束文档DTD约束字段，Schema约束类型，详细查看.dtd/.xsd文件写法
    }

    /**
     * 目录下搜索文件
     *
     * @param dir      目录
     * @param filename 要搜索的文件名称
     */
    public static void searchFile(File dir, String filename) throws IOException {
        //拦截非法情况
        if (dir == null || !dir.exists() || dir.isFile()) {
            return;
        }
        //获取目录下一级文件对象
        File[] files = dir.listFiles();
        //判断能否拿到一级文件对象
        if (files != null && files.length > 0) {
            //遍历
            for (File file : files) {
                //文件
                if (file.isFile()) {
                    //确认是否想要的
                    if (file.getName().contains(filename)) {
                        System.out.println(file.getAbsolutePath());
                        //启动
                        //Runtime runtime = Runtime.getRuntime();
                        //runtime.exec(file.getAbsolutePath());
                    }
                }
                //文件夹，递归
                else {
                    searchFile(file, filename);
                }
            }
        }
    }

    public static void deleteDir(File dir) {
        if (dir == null || !dir.exists()) {
            return;
        }
        if (dir.isFile()) {
            dir.delete();
            return;
        }

        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isFile()) {
                file.delete();
            } else {
                deleteDir(file);
            }
        }
        dir.delete();
    }

}
